home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / PEAR / PackageFileManager.php < prev    next >
Encoding:
PHP Script  |  2005-07-07  |  70.9 KB  |  1,595 lines

  1. <?php
  2. //
  3. // +------------------------------------------------------------------------+
  4. // | PEAR :: Package File Manager                                           |
  5. // +------------------------------------------------------------------------+
  6. // | Copyright (c) 2003-2004 Gregory Beaver                                 |
  7. // | Email         cellog@phpdoc.org                                        |
  8. // +------------------------------------------------------------------------+
  9. // | This source file is subject to version 3.00 of the PHP License,        |
  10. // | that is available at http://www.php.net/license/3_0.txt.               |
  11. // | If you did not receive a copy of the PHP license and are unable to     |
  12. // | obtain it through the world-wide-web, please send a note to            |
  13. // | license@php.net so we can mail you a copy immediately.                 |
  14. // +------------------------------------------------------------------------+
  15. // | Portions of this code based on phpDocumentor                           |
  16. // | Web           http://www.phpdoc.org                                    |
  17. // | Mirror        http://phpdocu.sourceforge.net/                          |
  18. // +------------------------------------------------------------------------+
  19. // $Id: PackageFileManager.php,v 1.42 2005/04/06 22:21:20 cellog Exp $
  20. //
  21.  
  22. /**
  23.  * @package PEAR_PackageFileManager
  24.  */
  25. /**
  26.  * PEAR installer
  27.  */
  28. require_once 'PEAR/Common.php';
  29. /**#@+
  30.  * Error Codes
  31.  */
  32. define('PEAR_PACKAGEFILEMANAGER_NOSTATE', 1);
  33. define('PEAR_PACKAGEFILEMANAGER_NOVERSION', 2);
  34. define('PEAR_PACKAGEFILEMANAGER_NOPKGDIR', 3);
  35. define('PEAR_PACKAGEFILEMANAGER_NOBASEDIR', 4);
  36. define('PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND', 5);
  37. define('PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE', 6);
  38. define('PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE', 7);
  39. define('PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE', 8);
  40. define('PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE', 9);
  41. define('PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE', 10);
  42. define('PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST', 11);
  43. define('PEAR_PACKAGEFILEMANAGER_NOCVSENTRIES', 12);
  44. define('PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST', 13);
  45. define('PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS', 14);
  46. define('PEAR_PACKAGEFILEMANAGER_NOPACKAGE', 15);
  47. define('PEAR_PACKAGEFILEMANAGER_WRONG_MROLE', 16);
  48. define('PEAR_PACKAGEFILEMANAGER_NOSUMMARY', 17);
  49. define('PEAR_PACKAGEFILEMANAGER_NODESC', 18);
  50. define('PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS', 19);
  51. define('PEAR_PACKAGEFILEMANAGER_NO_FILES', 20);
  52. define('PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING', 21);
  53. define('PEAR_PACKAGEFILEMANAGER_INVALID_PACKAGE', 22);
  54. define('PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE', 23);
  55. define('PEAR_PACKAGEFILEMANAGER_INVALID_ROLE', 24);
  56. define('PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE', 25);
  57. define('PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED', 26);
  58. define('PEAR_PACKAGEFILEMANAGER_NO_PHPCOMPATINFO', 27);
  59. /**#@-*/
  60. /**
  61.  * Error messages
  62.  * @global array $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS']
  63.  */
  64. $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'] =
  65. array(
  66.     'en' =>
  67.     array(
  68.         PEAR_PACKAGEFILEMANAGER_NOSTATE =>
  69.             'Release State (option \'state\') must by specified in PEAR_PackageFileManager setOptions (alpha|beta|stable)',
  70.         PEAR_PACKAGEFILEMANAGER_NOVERSION =>
  71.             'Release Version (option \'version\') must be specified in PEAR_PackageFileManager setOptions',
  72.         PEAR_PACKAGEFILEMANAGER_NOPKGDIR =>
  73.             'Package source base directory (option \'packagedirectory\') must be ' .
  74.             'specified in PEAR_PackageFileManager setOptions',
  75.         PEAR_PACKAGEFILEMANAGER_NOBASEDIR =>
  76.             'Package install base directory (option \'baseinstalldir\') must be ' .
  77.             'specified in PEAR_PackageFileManager setOptions',
  78.         PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND =>
  79.             'Base class "%s" can\'t be located',
  80.         PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE =>
  81.             'Base class "%s" can\'t be located in default or user-specified directories',
  82.         PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE =>
  83.             'Failed to write package.xml file to destination directory',
  84.         PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE =>
  85.             'Destination directory "%s" is unwritable',
  86.         PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE =>
  87.             'Failed to copy package.xml.tmp file to package.xml',
  88.         PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE =>
  89.             'Failed to open temporary file "%s" for writing',
  90.         PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST =>
  91.             'package.xml file path "%s" doesn\'t exist or isn\'t a directory',
  92.         PEAR_PACKAGEFILEMANAGER_NOCVSENTRIES =>
  93.             'Directory "%s" is not a CVS directory (it must have the CVS/Entries file)',
  94.         PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST =>
  95.             'Package source base directory "%s" doesn\'t exist or isn\'t a directory',
  96.         PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS =>
  97.             'Run $managerclass->setOptions() before any other methods',
  98.         PEAR_PACKAGEFILEMANAGER_NOPACKAGE =>
  99.             'Package Name (option \'package\') must by specified in PEAR_PackageFileManager '.
  100.             'setOptions to create a new package.xml',
  101.         PEAR_PACKAGEFILEMANAGER_NOSUMMARY =>
  102.             'Package Summary (option \'summary\') must by specified in PEAR_PackageFileManager' .
  103.             ' setOptions to create a new package.xml',
  104.         PEAR_PACKAGEFILEMANAGER_NODESC =>
  105.             'Detailed Package Description (option \'description\') must be' .
  106.             ' specified in PEAR_PackageFileManager setOptions to create a new package.xml',
  107.         PEAR_PACKAGEFILEMANAGER_WRONG_MROLE =>
  108.             'Maintainer role must be one of "%s", was "%s"',
  109.         PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS =>
  110.             'Add maintainers to a package before generating the package.xml',
  111.         PEAR_PACKAGEFILEMANAGER_NO_FILES =>
  112.             'No files found, check the path "%s"',
  113.         PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING =>
  114.             'No files left, check the path "%s" and ignore option "%s"',
  115.         PEAR_PACKAGEFILEMANAGER_INVALID_PACKAGE =>
  116.             'Package validation failed:%s%s',
  117.         PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE =>
  118.             'Replacement Type must be one of "%s", was passed "%s"',
  119.         PEAR_PACKAGEFILEMANAGER_INVALID_ROLE =>
  120.             'Invalid file role passed to addRole, must be one of "%s", was passed "%s"',
  121.         PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE =>
  122.             'addDependency had PHP as a package, use type="php"',
  123.         PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED =>
  124.             'path "%path%" contains CVS directory',
  125.         PEAR_PACKAGEFILEMANAGER_NO_PHPCOMPATINFO =>
  126.             'PHP_Compat is not installed, cannot detect dependencies',
  127.         ),
  128.         // other language translations go here
  129.      );
  130. /**
  131.  * PEAR :: PackageFileManager updates the <filelist></filelist> section
  132.  * of a PEAR package.xml file to reflect the current files in
  133.  * preparation for a release.
  134.  *
  135.  * The PEAR_PackageFileManager class uses a plugin system to generate the
  136.  * list of files in a package.  This allows both standard recursive
  137.  * directory parsing (plugin type file) and more intelligent options
  138.  * such as the CVS browser {@link PEAR_PackageFileManager_Cvs}, which
  139.  * grabs all files in a local CVS checkout to create the list, ignoring
  140.  * any other local files.
  141.  *
  142.  * Other options include specifying roles for file extensions (all .php
  143.  * files are role="php", for example), roles for directories (all directories
  144.  * named "tests" are given role="tests" by default), and exceptions.
  145.  * Exceptions are specific pathnames with * and ? wildcards that match
  146.  * a default role, but should have another.  For example, perhaps
  147.  * a debug.tpl template would normally be data, but should be included
  148.  * in the docs role.  Along these lines, to exclude files entirely,
  149.  * use the ignore option.
  150.  *
  151.  * Required options for a release include version, baseinstalldir, state,
  152.  * and packagedirectory (the full path to the local location of the
  153.  * package to create a package.xml file for)
  154.  *
  155.  * Example usage:
  156.  * <code>
  157.  * <?php
  158.  * require_once('PEAR/PackageFileManager.php');
  159.  * $packagexml = new PEAR_PackageFileManager;
  160.  * $e = $packagexml->setOptions(
  161.  * array('baseinstalldir' => 'PhpDocumentor',
  162.  *  'version' => '1.2.1',
  163.  *  'packagedirectory' => 'C:/Web Pages/chiara/phpdoc2/',
  164.  *  'state' => 'stable',
  165.  *  'filelistgenerator' => 'cvs', // generate from cvs, use file for directory
  166.  *  'notes' => 'We\'ve implemented many new and exciting features',
  167.  *  'ignore' => array('TODO', 'tests/'), // ignore TODO, all files in tests/
  168.  *  'installexceptions' => array('phpdoc' => '/*'), // baseinstalldir ="/" for phpdoc
  169.  *  'dir_roles' => array('tutorials' => 'doc'),
  170.  *  'exceptions' => array('README' => 'doc', // README would be data, now is doc
  171.  *                        'PHPLICENSE.txt' => 'doc'))); // same for the license
  172.  * if (PEAR::isError($e)) {
  173.  *     echo $e->getMessage();
  174.  *     die();
  175.  * }
  176.  * $e = $test->addPlatformException('pear-phpdoc.bat', 'windows');
  177.  * if (PEAR::isError($e)) {
  178.  *     echo $e->getMessage();
  179.  *     exit;
  180.  * }
  181.  * $packagexml->addRole('pkg', 'doc'); // add a new role mapping
  182.  * if (PEAR::isError($e)) {
  183.  *     echo $e->getMessage();
  184.  *     exit;
  185.  * }
  186.  * // replace @PHP-BIN@ in this file with the path to php executable!  pretty neat
  187.  * $e = $test->addReplacement('pear-phpdoc', 'pear-config', '@PHP-BIN@', 'php_bin');
  188.  * if (PEAR::isError($e)) {
  189.  *     echo $e->getMessage();
  190.  *     exit;
  191.  * }
  192.  * $e = $test->addReplacement('pear-phpdoc.bat', 'pear-config', '@PHP-BIN@', 'php_bin');
  193.  * if (PEAR::isError($e)) {
  194.  *     echo $e->getMessage();
  195.  *     exit;
  196.  * }
  197.  * // note use of {@link debugPackageFile()} - this is VERY important
  198.  * if (isset($_GET['make']) || (isset($_SERVER['argv'][2]) &&
  199.  *       $_SERVER['argv'][2] == 'make')) {
  200.  *     $e = $packagexml->writePackageFile();
  201.  * } else {
  202.  *     $e = $packagexml->debugPackageFile();
  203.  * }
  204.  * if (PEAR::isError($e)) {
  205.  *     echo $e->getMessage();
  206.  *     die();
  207.  * }
  208.  * ?>
  209.  * </code>
  210.  * 
  211.  * In addition, a package.xml file can now be generated from
  212.  * scratch, with the usage of new options package, summary, description, and
  213.  * the use of the {@link addMaintainer()} method
  214.  * @package PEAR_PackageFileManager
  215.  */
  216. class PEAR_PackageFileManager
  217. {
  218.     /**
  219.      * Format: array(array(regexp-ready string to search for whole path,
  220.      * regexp-ready string to search for basename of ignore strings),...)
  221.      * @var false|array
  222.      * @access private
  223.      */
  224.     var $_ignore = false;
  225.     
  226.     /**
  227.      * Contents of the package.xml file
  228.      * @var string
  229.      * @access private
  230.      */
  231.     var $_packageXml = false;
  232.     
  233.     /**
  234.      * Contents of the original package.xml file, if any
  235.      * @var string
  236.      * @access private
  237.      */
  238.     var $_oldPackageXml = false;
  239.     
  240.     /**
  241.      * @access private
  242.      * @var PEAR_Common
  243.      */
  244.     var $_pear;
  245.     
  246.     /**
  247.      * @access private
  248.      * @var array
  249.      */
  250.     var $_warningStack = array();
  251.  
  252.     /**
  253.      * flag used to determine whether to use PHP_CompatInfo to detect deps
  254.      * @var boolean
  255.      * @access private
  256.      */
  257.     var $_detectDependencies = false;
  258.     
  259.     /**
  260.      * @access private
  261.      * @var string
  262.      */
  263.     var $_options = array(
  264.                       'packagefile' => 'package.xml',
  265.                       'doctype' => 'http://pear.php.net/dtd/package-1.0',
  266.                       'filelistgenerator' => 'file',
  267.                       'license' => 'PHP License',
  268.                       'changelogoldtonew' => true,
  269.                       'roles' =>
  270.                         array(
  271.                             'php' => 'php',
  272.                             'html' => 'doc',
  273.                             '*' => 'data',
  274.                              ),
  275.                       'dir_roles' =>
  276.                         array(
  277.                             'docs' => 'doc',
  278.                             'examples' => 'doc',
  279.                             'tests' => 'test',
  280.                              ),
  281.                       'exceptions' => array(),
  282.                       'installexceptions' => array(),
  283.                       'installas' => array(),
  284.                       'platformexceptions' => array(),
  285.                       'scriptphaseexceptions' => array(),
  286.                       'ignore' => array(),
  287.                       'include' => false,
  288.                       'deps' => false,
  289.                       'maintainers' => false,
  290.                       'notes' => '',
  291.                       'changelognotes' => false,
  292.                       'outputdirectory' => false,
  293.                       'pathtopackagefile' => false,
  294.                       'lang' => 'en',
  295.                       'configure_options' => array(),
  296.                       'replacements' => array(),
  297.                       'pearcommonclass' => false,
  298.                       'simpleoutput' => false,
  299.                       'addhiddenfiles' => false,
  300.                       'cleardependencies' => false,
  301.                       );
  302.     
  303.     /**
  304.      * Does nothing, use setOptions
  305.      *
  306.      * The constructor is not used in order to be able to
  307.      * return a PEAR_Error from setOptions
  308.      * @see setOptions()
  309.      */
  310.     function PEAR_PackageFileManager()
  311.     {
  312.     }
  313.     
  314.     /**
  315.      * Set package.xml generation options
  316.      *
  317.      * The options array is indexed as follows:
  318.      * <code>
  319.      * $options = array('option_name' => <optionvalue>);
  320.      * </code>
  321.      *
  322.      * The documentation below simplifies this description through
  323.      * the use of option_name without quotes
  324.      *
  325.      * Configuration options:
  326.      * - lang: lang controls the language in which error messages are
  327.      *         displayed.  There are currently only English error messages,
  328.      *         but any contributed will be added over time.<br>
  329.      *         Possible values: en (default)
  330.      * - packagefile: the name of the packagefile, defaults to package.xml
  331.      * - pathtopackagefile: the path to an existing package file to read in,
  332.      *                      if different from the packagedirectory
  333.      * - packagedirectory: the path to the base directory of the package.  For
  334.      *                     package PEAR_PackageFileManager, this path is
  335.      *                     /path/to/pearcvs/pear/PEAR_PackageFileManager where
  336.      *                     /path/to/pearcvs is a local path on your hard drive
  337.      * - outputdirectory: the path in which to place the generated package.xml
  338.      *                    by default, this is ignored, and the package.xml is
  339.      *                    created in the packagedirectory
  340.      * - filelistgenerator: the <filelist> section plugin which will be used.
  341.      *                      In this release, there are two generator plugins,
  342.      *                      file and cvs.  For details, see the docs for these
  343.      *                      plugins
  344.      * - usergeneratordir: For advanced users.  If you write your own filelist
  345.      *                     generator plugin, use this option to tell
  346.      *                     PEAR_PackageFileManager where to find the file that
  347.      *                     contains it.  If the plugin is named foo, the class
  348.      *                     must be named PEAR_PackageFileManager_Foo
  349.      *                     no matter where it is located.  By default, the Foo
  350.      *                     plugin is located in PEAR/PackageFileManager/Foo.php.
  351.      *                     If you pass /path/to/foo in this option, setOptions
  352.      *                     will look for PEAR_PackageFileManager_Foo in
  353.      *                     /path/to/foo/Foo.php
  354.      * - doctype: Specifies the DTD of the package.xml file.  Default is
  355.      *            http://pear.php.net/dtd/package-1.0
  356.      * - pearcommonclass: Specifies the name of the class to instantiate, default
  357.      *                    is PEAR_Common, but users can override this with a custom
  358.      *                    class that implements PEAR_Common's method interface
  359.      * - changelogoldtonew: True if the ChangeLog should list from oldest entry to
  360.      *                      newest.  Set to false if you would like new entries first
  361.      * - simpleoutput: True if the package.xml should not contain md5sum or <provides />
  362.      *                 for readability
  363.      * - addhiddenfiles: True if you wish to add hidden files/directories that begin with .
  364.      *                   like .bashrc.  This is only used by the File generator.  The CVS
  365.      *                   generator will use all files in CVS regardless of format
  366.      *
  367.      * package.xml simple options:
  368.      * - baseinstalldir: The base directory to install this package in.  For
  369.      *                   package PEAR_PackageFileManager, this is "PEAR", for
  370.      *                   package PEAR, this is "/"
  371.      * - license: The license this release is released under.  Default is
  372.      *            PHP License if left unspecified
  373.      * - notes: Release notes, any text describing what makes this release unique
  374.      * - changelognotes: notes for the changelog, this should be more detailed than
  375.      *                   the release notes.  By default, PEAR_PackageFileManager uses
  376.      *                   the notes option for the changelog as well
  377.      * - version: The version number for this release.  Remember the convention for
  378.      *            numbering: initial alpha is between 0 and 1, add b<beta number> for
  379.      *            beta as in 1.0b1, the integer portion of the version should specify
  380.      *            backwards compatibility, as in 1.1 is backwards compatible with 1.0,
  381.      *            but 2.0 is not backwards compatible with 1.10.  Also note that 1.10
  382.      *            is a greater release version than 1.1 (think of it as "one point ten"
  383.      *            and "one point one").  Bugfix releases should be a third decimal as in
  384.      *            1.0.1, 1.0.2
  385.      * - package: [optional] Package name.  Use this to create a new package.xml, or
  386.      *            overwrite an existing one from another package used as a template
  387.      * - summary: [optional] Summary of package purpose
  388.      * - description: [optional] Description of package purpose.  Note that the above
  389.      *                three options are not optional when creating a new package.xml
  390.      *                from scratch
  391.      *
  392.      * <b>WARNING</b>: all complex options that require a file path are case-sensitive
  393.      *
  394.      * package.xml complex options:
  395.      * - cleardependencies: since version 1.3.0, this option will erase any existing
  396.      *                      dependencies in the package.xml if set to true
  397.      * - ignore: an array of filenames, directory names, or wildcard expressions specifying
  398.      *           files to exclude entirely from the package.xml.  Wildcards are operating system
  399.      *           wildcards * and ?.  file*foo.php will exclude filefoo.php, fileabrfoo.php and
  400.      *           filewho_is_thisfoo.php.  file?foo.php will exclude fileafoo.php and will not
  401.      *           exclude fileaafoo.php.  test/ will exclude all directories and subdirectories of
  402.      *           ANY directory named test encountered in directory parsing.  *test* will exclude
  403.      *           all files and directories that contain test in their name
  404.      * - include: an array of filenames, directory names, or wildcard expressions specifying
  405.      *            files to include in the listing.  All other files will be ignored.
  406.      *            Wildcards are in the same format as ignore
  407.      * - roles: this is an array mapping file extension to install role.  This
  408.      *          specifies default behavior that can be overridden by the exceptions
  409.      *          option and dir_roles option.  use {@link addRole()} to add a new
  410.      *          role to the pre-existing array
  411.      * - dir_roles: this is an array mapping directory name to install role.  All
  412.      *              files in a directory whose name matches the directory will be
  413.      *              given the install role specified.  Single files can be excluded
  414.      *              from this using the exceptions option.  The directory should be
  415.      *              a relative path from the baseinstalldir, or "/" for the baseinstalldir
  416.      * - exceptions: specify file role for specific files.  This array maps all files
  417.      *               matching the exact name of a file to a role as in "file.ext" => "role"
  418.      * - deps: dependency array.  Pass in an empty array to clear all dependencies, and use
  419.      *         {@link addDependency()} to add new ones/replace existing ones
  420.      * - maintainers: maintainers array.  Pass in an empty array to clear all maintainers, and
  421.      *                use {@link addMaintainer()} to add a new maintainer/replace existing maintainer
  422.      * - installexceptions: array mapping of specific filenames to baseinstalldir values.  Use
  423.      *                      this to force the installation of a file into another directory,
  424.      *                      such as forcing a script to be in the root scripts directory so that
  425.      *                      it will be in the path.  The filename must be a relative path to the
  426.      *                      packagedirectory
  427.      * - platformexceptions: array mapping of specific filenames to the platform they should be
  428.      *                       installed on.  Use this to specify unix-only files or windows-only
  429.      *                       files.  The format of the platform string must be
  430.      *                       OS-version-cpu-extra if any more specific information is needed,
  431.      *                       and the OS must be in lower case as in "windows."  The match is
  432.      *                       performed using a regular expression, but uses * and ? wildcards
  433.      *                       instead of .* and .?.  Note that hpux/aix/irix/linux are all
  434.      *                       exclusive.  To select non-windows, use (*ix|*ux)
  435.      * - scriptphaseexceptions: array mapping of scripts to their install phase.  This can be
  436.      *                          one of: pre-install, post-install, pre-uninstall, post-uninstall,
  437.      *                          pre-build, post-build, pre-setup, or post-setup
  438.      * - installas: array mapping of specific filenames to the filename they should be installed as.
  439.      *              Use this to specify new filenames for files that should be installed.  This will
  440.      *              often be used in conjunction with platformexceptions if there are two files for
  441.      *              different OSes that must have the same name when installed.
  442.      * - replacements: array mapping of specific filenames to complex text search-and-replace that
  443.      *                 should be performed upon install.  The format is:
  444.      *   <pre>
  445.      *   filename => array('type' => php-const|pear-config|package-info
  446.      *                     'from' => text in file
  447.      *                     'to' => name of variable)
  448.      *   </pre>
  449.      *                 if type is php-const, then 'to' must be the name of a PHP Constant.
  450.      *                 If type is pear-config, then 'to' must be the name of a PEAR config
  451.      *                 variable accessible through a PEAR_Config class->get() method.  If
  452.      *                 type is package-info, then 'to' must be the name of a section from
  453.      *                 the package.xml file used to install this file.
  454.      * - globalreplacements: a list of replacements that should be performed on every single file.
  455.      *                       The format is the same as replacements (since 1.4.0)
  456.      * - configure_options: array specifies build options for PECL packages (you should probably
  457.      *                      use PECL_Gen instead, but it's here for completeness)
  458.      * @see PEAR_PackageFileManager_File
  459.      * @see PEAR_PackageFileManager_CVS
  460.      * @return void|PEAR_Error
  461.      * @throws PEAR_PACKAGEFILEMANAGER_NOSTATE
  462.      * @throws PEAR_PACKAGEFILEMANAGER_NOVERSION
  463.      * @throws PEAR_PACKAGEFILEMANAGER_NOPKGDIR
  464.      * @throws PEAR_PACKAGEFILEMANAGER_NOBASEDIR
  465.      * @throws PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE
  466.      * @throws PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND
  467.      * @param array
  468.      */
  469.     function setOptions($options = array(), $internal = false)
  470.     {
  471.         if (!$internal) {
  472.             if (!isset($options['state'])) {
  473.                 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOSTATE);
  474.             }
  475.             if (!isset($options['version'])) {
  476.                 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOVERSION);
  477.             }
  478.         }
  479.         if (!isset($options['packagedirectory']) && !$internal) {
  480.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOPKGDIR);
  481.         } elseif (isset($options['packagedirectory'])) {
  482.             $options['packagedirectory'] = str_replace(DIRECTORY_SEPARATOR,
  483.                                                      '/',
  484.                                                      realpath($options['packagedirectory']));
  485.             if ($options['packagedirectory']{strlen($options['packagedirectory']) - 1} != '/') {
  486.                 $options['packagedirectory'] .= '/';
  487.             }
  488.         }
  489.         if (isset($options['pathtopackagefile'])) {
  490.             $options['pathtopackagefile'] = str_replace(DIRECTORY_SEPARATOR,
  491.                                                      '/',
  492.                                                      realpath($options['pathtopackagefile']));
  493.             if ($options['pathtopackagefile']{strlen($options['pathtopackagefile']) - 1} != '/') {
  494.                 $options['pathtopackagefile'] .= '/';
  495.             }
  496.         }
  497.         if (!isset($options['baseinstalldir']) && !$internal) {
  498.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOBASEDIR);
  499.         }
  500.         $this->_options = array_merge($this->_options, $options);
  501.         
  502.         if (!class_exists($this->_options['pearcommonclass'])) {
  503.             if ($this->_options['simpleoutput']) {
  504.                 if ($this->isIncludeable('PEAR/PackageFile/Generator/v1.php')) {
  505.                     include_once 'PEAR/PackageFileManager/SimpleGenerator.php';
  506.                     $this->_options['pearcommonclass'] = 'PEAR_PackageFileManager_SimpleGenerator';
  507.                 } else {
  508.                     include_once 'PEAR/PackageFileManager/XMLOutput.php';
  509.                     $this->_options['pearcommonclass'] = 'PEAR_PackageFileManager_XMLOutput';
  510.                 }
  511.             } else {
  512.                 $this->_options['pearcommonclass'] = 'PEAR_Common';
  513.             }
  514.         }
  515.         $path = ($this->_options['pathtopackagefile'] ?
  516.                     $this->_options['pathtopackagefile'] : $this->_options['packagedirectory']);
  517.         $this->_options['filelistgenerator'] =
  518.             ucfirst(strtolower($this->_options['filelistgenerator']));
  519.         if (!$internal) {
  520.             if (PEAR::isError($res =
  521.                   $this->_getExistingPackageXML($path, $this->_options['packagefile']))) {
  522.                 return $res;
  523.             }
  524.         }
  525.         if (!class_exists('PEAR_PackageFileManager_' . $this->_options['filelistgenerator'])) {
  526.             // attempt to load the interface from the standard PEAR location
  527.             if ($this->isIncludeable('PEAR/PackageFileManager/' .
  528.                   $this->_options['filelistgenerator'] . '.php')) {
  529.                 include_once('PEAR/PackageFileManager/' .
  530.                     $this->_options['filelistgenerator'] . '.php');
  531.             } elseif (isset($this->_options['usergeneratordir'])) {
  532.                 // attempt to load from a user-specified directory
  533.                 if (is_dir(realpath($this->_options['usergeneratordir']))) {
  534.                     $this->_options['usergeneratordir'] =
  535.                         str_replace(DIRECTORY_SEPARATOR,
  536.                                     '/',
  537.                                     realpath($this->_options['usergeneratordir']));
  538.                     if ($this->_options['usergeneratordir']{strlen($this->_options['usergeneratordir'])
  539.                           - 1} != '/') {
  540.                         $this->_options['usergeneratordir'] .= '/';
  541.                     }
  542.                 } else {
  543.                     $this->_options['usergeneratordir'] = '////';
  544.                 }
  545.                 if (file_exists($this->_options['usergeneratordir'] .
  546.                       $this->_options['filelistgenerator'] . '.php') &&
  547.                       is_readable($this->_options['usergeneratordir'] .
  548.                       $this->_options['filelistgenerator'] . '.php')) {
  549.                     include_once($this->_options['usergeneratordir'] .
  550.                         $this->_options['filelistgenerator'] . '.php');
  551.                 }
  552.                 if (!class_exists('PEAR_PackageFileManager_' . $this->_options['filelistgenerator'])) {
  553.                     return $this->raiseError(PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND_ANYWHERE,
  554.                             'PEAR_PackageFileManager_' . $this->_options['filelistgenerator']);
  555.                 }
  556.             } else {
  557.                 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_GENERATOR_NOTFOUND,
  558.                         'PEAR_PackageFileManager_' . $this->_options['filelistgenerator']);
  559.             }
  560.         }
  561.     }
  562.  
  563.     /**
  564.      * Import options from an existing package.xml
  565.      *
  566.      * @return true|PEAR_Error
  567.      */
  568.     function importOptions($packagefile, $options = array())
  569.     {
  570.         $options['cleardependencies'] = $options['deps'] = $options['maintainers'] = false;
  571.         $this->setOptions($options, true);
  572.         if (PEAR::isError($res = $this->_getExistingPackageXML(dirname($packagefile) .
  573.               DIRECTORY_SEPARATOR, basename($packagefile)))) {
  574.             return $res;
  575.         }
  576.         $this->_options['package'] = $this->_oldPackageXml['package'];
  577.         $this->_options['summary'] = $this->_oldPackageXml['summary'];
  578.         $this->_options['description'] = $this->_oldPackageXml['description'];
  579.         $this->_options['date'] = $this->_oldPackageXml['release_date'];
  580.         $this->_options['version'] = $this->_oldPackageXml['version'];
  581.         $this->_options['license'] = $this->_oldPackageXml['release_license'];
  582.         $this->_options['state'] = $this->_oldPackageXml['release_state'];
  583.         $this->_options['notes'] = $this->_oldPackageXml['release_notes'];
  584.         if (isset($this->_oldPackagexml['release_deps'])) {
  585.             $this->_options['deps'] = $this->_oldPackageXml['release_deps'];
  586.         }
  587.         $this->_options['maintainers'] = $this->_oldPackageXml['maintainers'];
  588.         return true;
  589.     }
  590.  
  591.     /**
  592.      * Get the existing options
  593.      * @return array
  594.      */
  595.     function getOptions()
  596.     {
  597.         return $this->_options;
  598.     }
  599.  
  600.     /**
  601.      * Add an extension/role mapping to the role mapping option
  602.      *
  603.      * Roles influence both where a file is installed and how it is installed.
  604.      * Files with role="data" are in a completely different directory hierarchy
  605.      * from the program files of role="php"
  606.      * 
  607.      * In PEAR 1.3b2, these roles are
  608.      * - php (most common)
  609.      * - data
  610.      * - doc
  611.      * - test
  612.      * - script (gives the file an executable attribute)
  613.      * - src
  614.      * @param string file extension
  615.      * @param string role
  616.      * @throws PEAR_PACKAGEFILEMANAGER_INVALID_ROLE
  617.      */
  618.     function addRole($extension, $role)
  619.     {
  620.         $roles = call_user_func(array($this->_options['pearcommonclass'], 'getfileroles'));
  621.         if (!in_array($role, $roles)) {
  622.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_ROLE, implode($roles, ', '), $role);
  623.         }
  624.         $this->_options['roles'][$extension] = $role;
  625.     }
  626.     
  627.     /**
  628.      * Add an install-time platform conditional install for a file
  629.      *
  630.      * The format of the platform string must be
  631.      * OS-version-cpu-extra if any more specific information is needed,
  632.      * and the OS must be in lower case as in "windows."  The match is
  633.      * performed using a regular expression, but uses * and ? wildcards
  634.      * instead of .* and .?.  Note that hpux/aix/irix/linux are all
  635.      * exclusive.  To select non-windows, use (*ix|*ux)
  636.      *
  637.      * This information is based on eyeing the source for OS/Guess.php, so
  638.      * if you are unsure of what to do, read that file.
  639.      * @param string relative path of file (relative to packagedirectory option)
  640.      * @param string platform descriptor string
  641.      */
  642.     function addPlatformException($path, $platform)
  643.     {
  644.         if (!isset($this->_options['platformexceptions'])) {
  645.             $this->_options['platformexceptions'] = array();
  646.         }
  647.         $this->_options['platformexceptions'][$path] = $platform;
  648.     }
  649.  
  650.     /**
  651.      * Add a replacement option for all files
  652.      *
  653.      * This sets an install-time complex search-and-replace function
  654.      * allowing the setting of platform-specific variables in all
  655.      * installed files.
  656.      *
  657.      * if $type is php-const, then $to must be the name of a PHP Constant.
  658.      * If $type is pear-config, then $to must be the name of a PEAR config
  659.      * variable accessible through a {@link PEAR_Config::get()} method.  If
  660.      * type is package-info, then $to must be the name of a section from
  661.      * the package.xml file used to install this file.
  662.      * @param string relative path of file (relative to packagedirectory option)
  663.      * @param string variable type, either php-const, pear-config or package-info
  664.      * @param string text to replace in the source file
  665.      * @param string variable name to use for replacement
  666.      * @throws PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE
  667.      */
  668.     function addGlobalReplacement($type, $from, $to)
  669.     {
  670.         if (!isset($this->_options['globalreplacements'])) {
  671.             $this->_options['globalreplacements'] = array();
  672.         }
  673.         $types = call_user_func(array($this->_options['pearcommonclass'], 'getreplacementtypes'));
  674.         if (!in_array($type, $types)) {
  675.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE,
  676.                 implode($types, ', '), $type);
  677.         }
  678.         $this->_options['globalreplacements'][] =
  679.             array('type' => $type, 'from' => $from, 'to' => $to);
  680.     }
  681.  
  682.     /**
  683.      * Add a replacement option for a file
  684.      *
  685.      * This sets an install-time complex search-and-replace function
  686.      * allowing the setting of platform-specific variables in an
  687.      * installed file.
  688.      *
  689.      * if $type is php-const, then $to must be the name of a PHP Constant.
  690.      * If $type is pear-config, then $to must be the name of a PEAR config
  691.      * variable accessible through a {@link PEAR_Config::get()} method.  If
  692.      * type is package-info, then $to must be the name of a section from
  693.      * the package.xml file used to install this file.
  694.      * @param string relative path of file (relative to packagedirectory option)
  695.      * @param string variable type, either php-const, pear-config or package-info
  696.      * @param string text to replace in the source file
  697.      * @param string variable name to use for replacement
  698.      * @throws PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE
  699.      */
  700.     function addReplacement($path, $type, $from, $to)
  701.     {
  702.         if (!isset($this->_options['replacements'])) {
  703.             $this->_options['replacements'] = array();
  704.         }
  705.         $types = call_user_func(array($this->_options['pearcommonclass'], 'getreplacementtypes'));
  706.         if (!in_array($type, $types)) {
  707.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_REPLACETYPE,
  708.                 implode($types, ', '), $type);
  709.         }
  710.         $this->_options['replacements'][$path][] = array('type' => $type, 'from' => $from, 'to' => $to);
  711.     }
  712.     
  713.     /**
  714.      * Add a maintainer to the list of maintainers.
  715.      *
  716.      * Every maintainer must have a valid account at pear.php.net.  The
  717.      * first parameter is the account name (for instance, cellog is the
  718.      * handle for Greg Beaver at pear.php.net).  Every maintainer has
  719.      * one of four possible roles:
  720.      * - lead: the primary maintainer
  721.      * - developer: an important developer on the project
  722.      * - contributor: self-explanatory
  723.      * - helper: ditto
  724.      *
  725.      * Finally, specify the name and email of the maintainer
  726.      * @param string username on pear.php.net of maintainer
  727.      * @param lead|developer|contributor|helper role of maintainer
  728.      * @param string full name of maintainer
  729.      * @param string email address of maintainer
  730.      */
  731.     function addMaintainer($handle, $role, $name, $email)
  732.     {
  733.         if (!$this->_packageXml) {
  734.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
  735.         }
  736.         if (!in_array($role, $GLOBALS['_PEAR_Common_maintainer_roles'])) {
  737.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_WRONG_MROLE,
  738.                 implode(', ', call_user_func(array($this->_options['pearcommonclass'],
  739.                     'getUserRoles'))),
  740.                 $role);
  741.         }
  742.         if (!isset($this->_packageXml['maintainers'])) {
  743.             $this->_packageXml['maintainers'] = array();
  744.         }
  745.         $found = false;
  746.         foreach($this->_packageXml['maintainers'] as $index => $maintainer) {
  747.             if ($maintainer['handle'] == $handle) {
  748.                 $found = $index;
  749.                 break;
  750.             }
  751.         }
  752.         $maintainer =
  753.             array('handle' => $handle, 'role' => $role, 'name' => $name, 'email' => $email);
  754.         if ($found !== false) {
  755.             $this->_packageXml['maintainers'][$found] = $maintainer;
  756.         } else {
  757.             $this->_packageXml['maintainers'][] = $maintainer;
  758.         }
  759.     }
  760.     
  761.     /**
  762.      * Add an install-time configuration option for building of source
  763.      *
  764.      * This option is only useful to PECL projects that are built upon
  765.      * installation
  766.      * @param string name of the option
  767.      * @param string prompt to display to the user
  768.      * @param string default value
  769.      * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
  770.      * @return void|PEAR_Error
  771.      */
  772.     function addConfigureOption($name, $prompt, $default = null)
  773.     {
  774.         if (!$this->_packageXml) {
  775.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
  776.         }
  777.         if (!isset($this->_packageXml['configure_options'])) {
  778.             $this->_packageXml['configure_options'] = array();
  779.         }
  780.         $found = false;
  781.         foreach($this->_packageXml['configure_options'] as $index => $option) {
  782.             if ($option['name'] == $name) {
  783.                 $found = $index;
  784.                 break;
  785.             }
  786.         }
  787.         $option = array('name' => $name, 'prompt' => $prompt);
  788.         if (isset($default)) {
  789.             $option['default'] = $default;
  790.         }
  791.         if ($found !== false) {
  792.             $this->_packageXml['configure_options'][$found] = $option;
  793.         } else {
  794.             $this->_packageXml['configure_options'][] = $option;
  795.         }
  796.     }
  797.  
  798.     /**
  799.      * @return void|PEAR_Error
  800.      * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
  801.      */
  802.     function detectDependencies()
  803.     {
  804.         if (!$this->_packageXml) {
  805.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
  806.         }
  807.         if (!$this->isIncludeable('PHP/CompatInfo.php')) {
  808.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_PHP_COMPAT_NOT_INSTALLED);
  809.         } else {
  810.             if (include_once('PHP/CompatInfo.php')) {
  811.                 $this->_detectDependencies = true;
  812.             } else {
  813.                 $this->raiseError(PEAR_PACKAGEFILEMANAGER_NO_PHPCOMPATINFO);
  814.             }
  815.         }
  816.     }
  817.  
  818.     function isIncludeable($file)
  819.     {
  820.         if (!defined('PATH_SEPARATOR')) {
  821.             define('PATH_SEPARATOR', strtolower(substr(PHP_OS, 0, 3)) == 'win' ? ';' : ':');
  822.         }
  823.         foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $path) {
  824.             if (file_exists($path . DIRECTORY_SEPARATOR . $file) &&
  825.                   is_readable($path . DIRECTORY_SEPARATOR . $file)) {
  826.                 return true;
  827.             }
  828.         }
  829.         return false;
  830.     }
  831.  
  832.     /**
  833.      * Add a dependency on another package, or an extension/php
  834.      *
  835.      * This will overwrite an existing dependency if it is found.  In
  836.      * other words, if a dependency on PHP 4.1.0 exists, and
  837.      * addDependency('php', '4.3.0', 'ge', 'php') is called, the existing
  838.      * dependency on PHP 4.1.0 will be overwritten with the new one on PHP 4.3.0
  839.      * @param string Dependency element name
  840.      * @param string Dependency version
  841.      * @param string A specific operator for the version, this can be one of:
  842.      *   'has', 'not', 'lt', 'le', 'eq', 'ne', 'ge', or 'gt'
  843.      * @param string Dependency type.  This can be one of:
  844.      *   'pkg', 'ext', 'php', 'prog', 'os', 'sapi', or 'zend'
  845.      * @param boolean true if dependency is optional
  846.      * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
  847.      * @throws PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE
  848.      * @return void|PEAR_Error
  849.      */
  850.     function addDependency($name, $version = false, $operator = 'ge', $type = 'pkg', $optional = false)
  851.     {
  852.         if (!$this->_packageXml) {
  853.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
  854.         }
  855.         if ((strtolower($name) == 'php') && (strtolower($type) == 'pkg')) {
  856.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_PHP_NOT_PACKAGE);
  857.         }
  858.         if (!isset($this->_packageXml['release_deps']) || !is_array($this->_packageXml['release_deps'])) {
  859.             $this->_packageXml['release_deps'] = array();
  860.         }
  861.         $found = false;
  862.         foreach($this->_packageXml['release_deps'] as $index => $dep) {
  863.             if ($type == 'php') {
  864.                 if ($dep['type'] == 'php') {
  865.                     $found = $index;
  866.                     break;
  867.                 }
  868.             } else {
  869.                 if (isset($dep['name']) && $dep['name'] == $name && $dep['type'] == $type) {
  870.                     $found = $index;
  871.                     break;
  872.                 }
  873.             }
  874.         }
  875.         $dep =
  876.             array(
  877.                 'name' => $name,
  878.                 'type' => $type);
  879.         if ($type == 'php') {
  880.             unset($dep['name']);
  881.         }
  882.         if ($operator) {
  883.             $dep['rel'] = $operator;
  884.             if ($dep['rel'] != 'has' && $version) {
  885.                 $dep['version'] = $version;
  886.             }
  887.         }
  888.         
  889.         if ($optional) {
  890.             $dep['optional'] = 'yes';
  891.         } else {
  892.             $dep['optional'] = 'no';
  893.         }
  894.  
  895.         if ($found !== false) {
  896.             $this->_packageXml['release_deps'][$found] = $dep; // overwrite existing dependency
  897.         } else {
  898.             $this->_packageXml['release_deps'][] = $dep; // add new dependency
  899.         }
  900.     }
  901.  
  902.     /**
  903.      * Writes the package.xml file out with the newly created <release></release> tag
  904.      *
  905.      * ALWAYS use {@link debugPackageFile} to verify that output is correct before
  906.      * overwriting your package.xml
  907.      * @param boolean null if no debugging, true if web interface, false if command-line
  908.      * @throws PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS
  909.      * @throws PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS
  910.      * @throws PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE
  911.      * @throws PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE
  912.      * @throws PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE
  913.      * @throws PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE
  914.      * @return void|PEAR_Error
  915.      */
  916.     function writePackageFile($debuginterface = null)
  917.     {
  918.         if (!$this->_packageXml) {
  919.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
  920.         }
  921.         if (!isset($this->_packageXml['maintainers']) || empty($this->_packageXml['maintainers'])) {
  922.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_ADD_MAINTAINERS);
  923.         }
  924.         extract($this->_options);
  925.         $date = date('Y-m-d');
  926.         if (isset($package)) {
  927.             $this->_packageXml['package'] = $package;
  928.         }
  929.         if (isset($summary)) {
  930.             $this->_packageXml['summary'] = $summary;
  931.         }
  932.         if (isset($description)) {
  933.             $this->_packageXml['description'] = $description;
  934.         }
  935.         $this->_packageXml['release_date'] = $date;
  936.         $this->_packageXml['version'] = $version;
  937.         $this->_packageXml['release_license'] = $license;
  938.         $this->_packageXml['release_state'] = $state;
  939.         $this->_packageXml['release_notes'] = $notes;
  940.         $PEAR_Common = $this->_options['pearcommonclass'];
  941.         $this->_pear = new $PEAR_Common;
  942.         if (method_exists($this->_pear, 'setPackageFileManager')) {
  943.             $this->_pear->setPackageFileManager($this);
  944.         }
  945.         $this->_packageXml['filelist'] = $this->_getFileList();
  946.         $warnings = $this->getWarnings();
  947.         if (count($warnings)) {
  948.             $nl = (isset($debuginterface) && $debuginterface ? '<br />' : "\n");
  949.             foreach($warnings as $errmsg) {
  950.                 echo 'WARNING: ' . $errmsg['message'] . $nl;
  951.             }
  952.         }
  953.         if (PEAR::isError($this->_packageXml['filelist'])) {
  954.             return $this->_packageXml['filelist'];
  955.         }
  956.         if (isset($this->_pear->pkginfo['provides'])) {
  957.             $this->_packageXml['provides'] = $this->_pear->pkginfo['provides'];
  958.         }
  959.         if ($this->_options['simpleoutput']) {
  960.             unset($this->_packageXml['provides']);
  961.         }
  962.         $this->_packageXml['release_deps'] = $this->_getDependencies();
  963.         $this->_updateChangeLog();
  964.         
  965.         $common = &$this->_pear;
  966.         $warnings = $errors = array();
  967.         if (method_exists($common, 'setPackageFileManagerOptions')) {
  968.             $common->setPackageFileManagerOptions($this->_options);
  969.         }
  970.         $packagexml = $common->xmlFromInfo($this->_packageXml);
  971.         $common->validatePackageInfo($packagexml, $warnings, $errors,
  972.             $this->_options['packagedirectory']);
  973.         if (count($errors)) {
  974.             $ret = '';
  975.             $nl = (isset($debuginterface) && $debuginterface ? '<br />' : "\n");
  976.             foreach($errors as $errmsg) {
  977.                 $ret .= $errmsg . $nl;
  978.             }
  979.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_INVALID_PACKAGE, $nl, $ret);
  980.         }
  981.         if (count($warnings)) {
  982.             $nl = (isset($debuginterface) && $debuginterface ? '<br />' : "\n");
  983.             foreach($warnings as $errmsg) {
  984.                 echo $errmsg . $nl;
  985.             }
  986.         }
  987.         if (!strpos($packagexml, '<!DOCTYPE')) {
  988.             // hack to fix pear
  989.             $packagexml = str_replace('<package version="1.0">',
  990.                 '<!DOCTYPE package SYSTEM "' . $this->_options['doctype'] .
  991.                 "\">\n<package version=\"1.0\">",
  992.                 $packagexml);
  993.         }
  994.         if (isset($debuginterface)) {
  995.             if ($debuginterface) {
  996.                 echo '<pre>' . htmlentities($packagexml) . '</pre>';
  997.             } else {
  998.                 echo $packagexml;
  999.             }
  1000.             return true;
  1001.         }
  1002.         $outputdir = ($this->_options['outputdirectory'] ?
  1003.                         $this->_options['outputdirectory'] : $this->_options['packagedirectory']);
  1004.         if ((file_exists($outputdir . $this->_options['packagefile']) &&
  1005.                 is_writable($outputdir . $this->_options['packagefile']))
  1006.                 ||
  1007.                 @touch($outputdir . $this->_options['packagefile'])) {
  1008.             if ($fp = @fopen($outputdir . $this->_options['packagefile'] . '.tmp', "w")) {
  1009.                 $written = @fwrite($fp, $packagexml);
  1010.                 @fclose($fp);
  1011.                 if ($written === false) {
  1012.                     return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTWRITE_PKGFILE);
  1013.                 }
  1014.                 if (!@copy($outputdir . $this->_options['packagefile'] . '.tmp',
  1015.                         $outputdir . $this->_options['packagefile'])) {
  1016.                     return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTCOPY_PKGFILE);
  1017.                 } else {
  1018.                     @unlink($outputdir . $this->_options['packagefile'] . '.tmp');
  1019.                     return true;
  1020.                 }
  1021.             } else {
  1022.                 return $this->raiseError(PEAR_PACKAGEFILEMANAGER_CANTOPEN_TMPPKGFILE,
  1023.                     $outputdir . $this->_options['packagefile'] . '.tmp');
  1024.             }
  1025.         } else {
  1026.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_DEST_UNWRITABLE, $outputdir);
  1027.         }
  1028.     }
  1029.     
  1030.     /**
  1031.      * ALWAYS use this to test output before overwriting your package.xml!!
  1032.      *
  1033.      * This method instructs writePackageFile() to simply print the package.xml
  1034.      * to output, either command-line or web-friendly (this is automatic
  1035.      * based on the value of php_sapi_name())
  1036.      * @uses writePackageFile() calls with the debug parameter set based on
  1037.      *       whether it is called from the command-line or web interface
  1038.      */
  1039.     function debugPackageFile()
  1040.     {
  1041.         $webinterface = php_sapi_name() != 'cli';
  1042.         return $this->writePackageFile($webinterface);
  1043.     }
  1044.     
  1045.     /**
  1046.      * Store a warning on the warning stack
  1047.      */
  1048.     function pushWarning($code, $info)
  1049.     {
  1050.         $this->_warningStack[] = array('code' => $code,
  1051.                                        'message' => $this->_getMessage($code, $info));
  1052.     }
  1053.     
  1054.     /**
  1055.      * Retrieve the list of warnings
  1056.      * @return array
  1057.      */
  1058.     function getWarnings()
  1059.     {
  1060.         $a = $this->_warningStack;
  1061.         $this->_warningStack = array();
  1062.         return $a;
  1063.     }
  1064.     
  1065.     /**
  1066.      * Retrieve an error message from a code
  1067.      * @access private
  1068.      * @return string Error message
  1069.      */
  1070.     function _getMessage($code, $info)
  1071.     {
  1072.         $msg = $GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'][$this->_options['lang']][$code];
  1073.         foreach ($info as $name => $value) {
  1074.             $msg = str_replace('%' . $name . '%', $value, $msg);
  1075.         }
  1076.         return $msg;
  1077.     }
  1078.     
  1079.     /**
  1080.      * Utility function to shorten error generation code
  1081.      *
  1082.      * {@source}
  1083.      * @return PEAR_Error
  1084.      * @static
  1085.      */
  1086.     function raiseError($code, $i1 = '', $i2 = '')
  1087.     {
  1088.         return PEAR::raiseError('PEAR_PackageFileManager Error: ' .
  1089.                     sprintf($GLOBALS['_PEAR_PACKAGEFILEMANAGER_ERRORS'][$this->_options['lang']][$code],
  1090.                     $i1, $i2), $code);
  1091.     }
  1092.     
  1093.     /**
  1094.      * Uses {@link PEAR_Common::analyzeSourceCode()} and {@link PEAR_Common::buildProvidesArray()}
  1095.      * to create the <provides></provides> section of the package.xml
  1096.      * @param PEAR_Common
  1097.      * @param string path to source file
  1098.      * @access private
  1099.      */
  1100.     function _addProvides(&$pear, $file)
  1101.     {
  1102.         if (!($a = $pear->analyzeSourceCode($file))) {
  1103.             return;
  1104.         } else {
  1105.             $pear->buildProvidesArray($a);
  1106.         }
  1107.     }
  1108.     
  1109.     /**
  1110.      * @uses getDirTag() generate the xml from the array
  1111.      * @return string
  1112.      * @access private
  1113.      */
  1114.     function _getFileList()
  1115.     {
  1116.         $generatorclass = 'PEAR_PackageFileManager_' . $this->_options['filelistgenerator'];
  1117.         $generator = new $generatorclass($this, $this->_options);
  1118.         if ($this->_options['simpleoutput'] && is_a($this->_pear, 'PEAR_Common')) {
  1119.             return $this->_getSimpleDirTag($this->_struc = $generator->getFileList());
  1120.         }
  1121.         return $this->_getDirTag($this->_struc = $generator->getFileList()); 
  1122.     }
  1123.     
  1124.     /**
  1125.      * Recursively generate the <filelist> section's <dir> and <file> tags, but with
  1126.      * simple human-readable output
  1127.      * @param array|PEAR_Error the sorted directory structure, or an error
  1128.      *                         from filelist generation
  1129.      * @param false|string whether the parent directory has a role this should
  1130.      * inherit
  1131.      * @param integer indentation level
  1132.      * @return array|PEAR_Error
  1133.      * @access private
  1134.      */
  1135.     function _getSimpleDirTag($struc, $role = false, $_curdir = '')
  1136.     {
  1137.         if (PEAR::isError($struc)) {
  1138.             return $struc;
  1139.         }
  1140.         extract($this->_options);
  1141.         $ret = array();
  1142.         foreach($struc as $dir => $files) {
  1143.             if (false && $dir === '/') {
  1144.                 // global directory role? overrides all exceptions except file exceptions
  1145.                 if (isset($dir_roles['/'])) {
  1146.                     $role = $dir_roles['/'];
  1147.                 }
  1148.                 return array(
  1149.                     'baseinstalldir' => $this->_options['baseinstalldir'],
  1150.                     '##files' => $this->_getSimpleDirTag($struc[$dir], $role, ''),
  1151.                     'name' => '/');
  1152.             } else {
  1153.                 if (!isset($files['file'])) {
  1154.                     if (isset($dir_roles[$_curdir . $dir])) {
  1155.                         $myrole = $dir_roles[$_curdir . $dir];
  1156.                     } else {
  1157.                         $myrole = $role;
  1158.                     }
  1159.                     $ret[$dir] = array();
  1160.                     if ($dir == '/') {
  1161.                         $ret[$dir]['baseinstalldir'] = $this->_options['baseinstalldir'];
  1162.                     }
  1163.                     $ret[$dir]['name'] = $dir;
  1164.                     $recurdir = ($_curdir == '') ? $dir . '/' : $_curdir . $dir . '/';
  1165.                     if ($recurdir == '//') {
  1166.                         $recurdir = '';
  1167.                     }
  1168.                     $ret[$dir]['##files'] = $this->_getSimpleDirTag($files, $myrole, $recurdir);
  1169.                 } else {
  1170.                     $myrole = '';
  1171.                     if (!$role)
  1172.                     {
  1173.                         $myrole = false;
  1174.                         if (isset($exceptions[$files['path']])) {
  1175.                             $myrole = $exceptions[$files['path']];
  1176.                         } elseif (isset($roles[$files['ext']])) {
  1177.                             $myrole = $roles[$files['ext']];
  1178.                         } else {
  1179.                             $myrole = $roles['*'];
  1180.                         }
  1181.                     } else {
  1182.                         $myrole = $role;
  1183.                         if (isset($exceptions[$files['path']])) {
  1184.                             $myrole = $exceptions[$files['path']];
  1185.                         }
  1186.                     }
  1187.                     $test = explode('/', $files['path']);
  1188.                     foreach ($test as $subpath) {
  1189.                         if ($subpath == 'CVS') {
  1190.                             $this->pushWarning(PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED,
  1191.                                 array('path' => $files['path']));
  1192.                         }
  1193.                     }
  1194.                     $ret[$files['file']] = array('role' => $myrole);
  1195.                     if (isset($installexceptions[$files['path']])) {
  1196.                         $ret[$files['file']]['baseinstalldir'] =
  1197.                             $installexceptions[$files['path']];
  1198.                     }
  1199.                     if (isset($platformexceptions[$files['path']])) {
  1200.                         $ret[$files['file']]['platform'] = $platformexceptions[$files['path']];
  1201.                     }
  1202.                     if (isset($installas[$files['path']])) {
  1203.                         $ret[$files['file']]['install-as'] = $installas[$files['path']];
  1204.                     }
  1205.                     if (isset($replacements[$files['path']])) {
  1206.                         $ret[$files['file']]['replacements'] = $replacements[$files['path']];
  1207.                     }
  1208.                     if (isset($globalreplacements)) {
  1209.                         if (!isset($ret[$files['file']]['replacements'])) {
  1210.                             $ret[$files['file']]['replacements'] = array();
  1211.                         }
  1212.                         $ret[$files['file']]['replacements'] = array_merge(
  1213.                             $ret[$files['file']]['replacements'], $globalreplacements);
  1214.                     }
  1215.                 }
  1216.             }
  1217.         }
  1218.         return $ret;
  1219.     }
  1220.     
  1221.     /**
  1222.      * Recursively generate the <filelist> section's <dir> and <file> tags
  1223.      * @param array|PEAR_Error the sorted directory structure, or an error
  1224.      *                         from filelist generation
  1225.      * @param false|string whether the parent directory has a role this should
  1226.      * inherit
  1227.      * @param integer indentation level
  1228.      * @return array|PEAR_Error
  1229.      * @access private
  1230.      */
  1231.     function _getDirTag($struc, $role=false, $_curdir = '')
  1232.     {
  1233.         if (PEAR::isError($struc)) {
  1234.             return $struc;
  1235.         }
  1236.         extract($this->_options);
  1237.         $ret = array();
  1238.         foreach($struc as $dir => $files) {
  1239.             if ($dir === '/') {
  1240.                 // global directory role? overrides all exceptions except file exceptions
  1241.                 if (isset($dir_roles['/'])) {
  1242.                     $role = $dir_roles['/'];
  1243.                 }
  1244.                 return $this->_getDirTag($struc[$dir], $role, '');
  1245.             } else {
  1246.                 if (!isset($files['file'])) {
  1247.                     $myrole = '';
  1248.                     if (isset($dir_roles[$_curdir . $dir])) {
  1249.                         $myrole = $dir_roles[$_curdir . $dir];
  1250.                     } elseif ($role) {
  1251.                         $myrole = $role;
  1252.                     }
  1253.                     $ret = array_merge($ret, $this->_getDirTag($files, $myrole, $_curdir . $dir . '/'));
  1254.                 } else {
  1255.                     $myrole = '';
  1256.                     if (!$role)
  1257.                     {
  1258.                         $myrole = false;
  1259.                         if (isset($exceptions[$files['path']])) {
  1260.                             $myrole = $exceptions[$files['path']];
  1261.                         } elseif (isset($roles[$files['ext']])) {
  1262.                             $myrole = $roles[$files['ext']];
  1263.                         } else {
  1264.                             $myrole = $roles['*'];
  1265.                         }
  1266.                     } else {
  1267.                         $myrole = $role;
  1268.                         if (isset($exceptions[$files['path']])) {
  1269.                             $myrole = $exceptions[$files['path']];
  1270.                         }
  1271.                     }
  1272.                     if (isset($installexceptions[$files['path']])) {
  1273.                         $bi = $installexceptions[$files['path']];
  1274.                     } else {
  1275.                         $bi = $this->_options['baseinstalldir'];
  1276.                     }
  1277.                     $test = explode('/', $files['path']);
  1278.                     foreach ($test as $subpath) {
  1279.                         if ($subpath == 'CVS') {
  1280.                             $this->pushWarning(PEAR_PACKAGEFILEMANAGER_CVS_PACKAGED, array('path' => $files['path']));
  1281.                         }
  1282.                     }
  1283.                     $ret[$files['path']] =
  1284.                         array('role' => $myrole,
  1285.                               'baseinstalldir' => $bi,
  1286.                               );
  1287.                     if (!isset($this->_options['simpleoutput'])) {
  1288.                         $md5sum = @md5_file($this->_options['packagedirectory'] . $files['path']);
  1289.                         if (!empty($md5sum)) {
  1290.                             $ret[$files['path']]['md5sum'] = $md5sum;
  1291.                         }
  1292.                     } elseif (isset($ret[$files['path']]['md5sum'])) {
  1293.                         unset($ret[$files['path']]['md5sum']);
  1294.                     }
  1295.                     if (isset($platformexceptions[$files['path']])) {
  1296.                         $ret[$files['path']]['platform'] = $platformexceptions[$files['path']];
  1297.                     }
  1298.                     if (isset($installas[$files['path']])) {
  1299.                         $ret[$files['path']]['install-as'] = $installas[$files['path']];
  1300.                     }
  1301.                     if (isset($replacements[$files['path']])) {
  1302.                         $ret[$files['path']]['replacements'] = $replacements[$files['path']];
  1303.                     }
  1304.                     if (isset($globalreplacements)) {
  1305.                         if (!isset($ret[$files['path']]['replacements'])) {
  1306.                             $ret[$files['path']]['replacements'] = array();
  1307.                         }
  1308.                         $ret[$files['path']]['replacements'] = array_merge(
  1309.                             $ret[$files['path']]['replacements'], $globalreplacements);
  1310.                     }
  1311.                     if ($myrole == 'php' && !$this->_options['simpleoutput']) {
  1312.                         $this->_addProvides($this->_pear, $files['fullpath']);
  1313.                     }
  1314.                 }
  1315.             }
  1316.         }
  1317.         return $ret;
  1318.     }
  1319.  
  1320.     /**
  1321.      * @param array
  1322.      * @access private
  1323.      */
  1324.     function _traverseFileArray($files, &$ret) {
  1325.         foreach ($files as $file) {
  1326.             if (!isset($file['fullpath'])) {
  1327.                 $this->_traverseFileArray($file, $ret);
  1328.             } else {
  1329.                 $ret[] = $file['fullpath'];
  1330.             }
  1331.         }
  1332.     }
  1333.  
  1334.     /**
  1335.      * Retrieve the 'deps' option passed to the constructor
  1336.      * @access private
  1337.      * @return array
  1338.      */
  1339.     function _getDependencies()
  1340.     {
  1341.         if ($this->_detectDependencies) {
  1342.             $this->_traverseFileArray($this->_struc, $ret);
  1343.             $compatinfo = new PHP_CompatInfo();
  1344.             $info = $compatinfo->parseArray($ret);
  1345.             $ret = $this->addDependency('php',$info['version'],'ge','php',false);
  1346.             if (is_a($ret, 'PEAR_Error')) {
  1347.                 return $ret;
  1348.             }
  1349.             foreach ($info['extensions'] as $ext) {
  1350.                 $this->addDependency($ext, '', 'has', 'ext', false);
  1351.             }
  1352.         }
  1353.         if (isset($this->_packageXml['release_deps']) &&
  1354.               is_array($this->_packageXml['release_deps'])) {
  1355.             return $this->_packageXml['release_deps'];
  1356.         } else {
  1357.             return array();
  1358.         }
  1359.     }
  1360.  
  1361.     /**
  1362.      * Creates a changelog entry with the current release
  1363.      * notes and dates, or overwrites a previous creation
  1364.      * @access private
  1365.      */
  1366.     function _updateChangeLog()
  1367.     {
  1368.         $curlog = $oldchangelog = false;
  1369.         if (!isset($this->_packageXml['changelog'])) {
  1370.             $changelog = array();
  1371.             if (isset($this->_oldPackageXml['release_notes'])) {
  1372.                 $changelog['release_notes'] = $this->_oldPackageXml['release_notes'];
  1373.             }
  1374.             if (isset($this->_oldPackageXml['version'])) {
  1375.                 $changelog['version'] = $this->_oldPackageXml['version'];
  1376.             }
  1377.             if (isset($this->_oldPackageXml['release_date'])) {
  1378.                 $changelog['release_date'] = $this->_oldPackageXml['release_date'];
  1379.             }
  1380.             if (isset($this->_oldPackageXml['release_license'])) {
  1381.                 $changelog['release_license'] = $this->_oldPackageXml['release_license'];
  1382.             }
  1383.             if (isset($this->_oldPackageXml['release_state'])) {
  1384.                 $changelog['release_state'] = $this->_oldPackageXml['release_state'];
  1385.             }
  1386.             if (count($changelog)) {
  1387.                 $this->_packageXml['changelog'] = array($changelog);
  1388.             } else {
  1389.                 $this->_packageXml['changelog'] = array();
  1390.             }
  1391.         } else {
  1392.             if (isset($this->_oldPackageXml['release_notes'])) {
  1393.                 $oldchangelog['release_notes'] = $this->_oldPackageXml['release_notes'];
  1394.             }
  1395.             if (isset($this->_oldPackageXml['version'])) {
  1396.                 $oldchangelog['version'] = $this->_oldPackageXml['version'];
  1397.             }
  1398.             if (isset($this->_oldPackageXml['release_date'])) {
  1399.                 $oldchangelog['release_date'] = $this->_oldPackageXml['release_date'];
  1400.             }
  1401.             if (isset($this->_oldPackageXml['release_license'])) {
  1402.                 $oldchangelog['release_license'] = $this->_oldPackageXml['release_license'];
  1403.             }
  1404.             if (isset($this->_oldPackageXml['release_state'])) {
  1405.                 $oldchangelog['release_state'] = $this->_oldPackageXml['release_state'];
  1406.             }
  1407.         }
  1408.         $hasoldversion = false;
  1409.         foreach($this->_packageXml['changelog'] as $index => $changelog) {
  1410.             if ($oldchangelog && isset($oldchangelog['version']) 
  1411.                     && strnatcasecmp($oldchangelog['version'], $changelog['version']) == 0) {
  1412.                 $hasoldversion = true;
  1413.             }
  1414.             if (isset($changelog['version']) && strnatcasecmp($changelog['version'], $this->_options['version']) == 0) {
  1415.                 $curlog = $index;
  1416.             }
  1417.             if (isset($this->_packageXml['changelog'][$index]['release_notes'])) {
  1418.                 $this->_packageXml['changelog'][$index]['release_notes'] = trim($changelog['release_notes']);
  1419.             }
  1420.             // the parsing of the release notes adds a \n for some reason
  1421.         }
  1422.         if (!$hasoldversion && $oldchangelog && count($oldchangelog)
  1423.               && $oldchangelog['version'] != $this->_options['version']) {
  1424.             $this->_packageXml['changelog'][] = $oldchangelog;
  1425.         }
  1426.         $notes = ($this->_options['changelognotes'] ?
  1427.                     $this->_options['changelognotes'] : $this->_options['notes']);
  1428.         $changelog = array('version' => $this->_options['version'],
  1429.                            'release_date' => date('Y-m-d'),
  1430.                            'release_license' => $this->_options['license'],
  1431.                            'release_state' => $this->_options['state'],
  1432.                            'release_notes' => $notes,
  1433.                            );
  1434.         if ($curlog !== false) {
  1435.             $this->_packageXml['changelog'][$curlog] = $changelog;
  1436.         } else {
  1437.             $this->_packageXml['changelog'][] = $changelog;
  1438.         }
  1439.         usort($this->_packageXml['changelog'], array($this, '_changelogsort'));
  1440.     }
  1441.     
  1442.     /**
  1443.      * @static
  1444.      * @access private
  1445.      */
  1446.     function _changelogsort($a, $b)
  1447.     {
  1448.         if ($this->_options['changelogoldtonew']) {
  1449.             $c = strtotime($a['release_date']);
  1450.             $d = strtotime($b['release_date']);
  1451.             $v1 = $a['version'];
  1452.             $v2 = $b['version'];
  1453.          } else {
  1454.             $d = strtotime($a['release_date']);
  1455.             $c = strtotime($b['release_date']);
  1456.             $v2 = $a['version'];
  1457.             $v1 = $b['version'];
  1458.         }
  1459.         if ($c - $d > 0) {
  1460.             return 1;
  1461.         } elseif ($c - $d < 0) {
  1462.             return -1;
  1463.          }
  1464.         return version_compare($v1, $v2);
  1465.     }
  1466.  
  1467.     /**
  1468.      * @return true|PEAR_Error
  1469.      * @uses _generateNewPackageXML() if no package.xml is found, it
  1470.      *       calls this to create a new one
  1471.      * @param string full path to package file
  1472.      * @param string name of package file
  1473.      * @throws PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST
  1474.      * @access private
  1475.      */
  1476.     function _getExistingPackageXML($path, $packagefile = 'package.xml')
  1477.     {
  1478.         if (is_string($path) && is_dir($path)) {
  1479.             $contents = false;
  1480.             if (file_exists($path . $packagefile)) {
  1481.                 $contents = file_get_contents($path . $packagefile);
  1482.             }
  1483.             if (!$contents) {
  1484.                 return $this->_generateNewPackageXML();
  1485.             } else {
  1486.                 $PEAR_Common = $this->_options['pearcommonclass'];
  1487.                 if (!class_exists($PEAR_Common)) {
  1488.                     return $this->raiseError(PEAR_PACKAGEFILEMANAGER_RUN_SETOPTIONS);
  1489.                 }
  1490.                 $common = new $PEAR_Common;
  1491.                 if (is_a($common, 'PEAR_Common')) {
  1492.                     $this->_oldPackageXml =
  1493.                     $this->_packageXml = $common->infoFromString($contents);
  1494.                 } else { // new way
  1495.                     require_once 'PEAR/PackageFile.php';
  1496.                     $z = &PEAR_Config::singleton();
  1497.                     $pkg = &new PEAR_PackageFile($z);
  1498.                     $pf = &$pkg->fromXmlString($contents, PEAR_VALIDATE_DOWNLOADING, $path . $packagefile);
  1499.                     if (PEAR::isError($pf)) {
  1500.                         return $pf;
  1501.                     }
  1502.                     if ($pf->getPackagexmlVersion() != '1.0') {
  1503.                         return PEAR::raiseError('PEAR_PackageFileManager can only manage ' .
  1504.                             'package.xml version 1.0, use PEAR_PackageFileManager_v2 for newer' .
  1505.                             ' package files');
  1506.                     }
  1507.                     $this->_oldPackageXml =
  1508.                     $this->_packageXml = $pf->toArray();
  1509.                 }
  1510.                 if (PEAR::isError($this->_packageXml)) {
  1511.                     return $this->_packageXml;
  1512.                 }
  1513.                 if ($this->_options['cleardependencies']) {
  1514.                     $this->_packageXml['release_deps'] = $this->_options['deps'];
  1515.                 }
  1516.                 if ($this->_options['deps'] !== false) {
  1517.                     $this->_packageXml['release_deps'] = $this->_options['deps'];
  1518.                 } else {
  1519.                     if (isset($this->_packageXml['release_deps'])) {
  1520.                         $this->_options['deps'] = $this->_packageXml['release_deps'];
  1521.                     }
  1522.                 }
  1523.                 if ($this->_options['maintainers'] !== false) {
  1524.                     $this->_packageXml['maintainers'] = $this->_options['maintainers'];
  1525.                 } else {
  1526.                     $this->_options['maintainers'] = $this->_packageXml['maintainers'];
  1527.                 }
  1528.                 unset($this->_packageXml['filelist']);
  1529.                 unset($this->_packageXml['provides']);
  1530.             }
  1531.             return true;
  1532.         } else {
  1533.             if (!is_string($path)) {
  1534.                 $path = gettype($path);
  1535.             }
  1536.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_PATH_DOESNT_EXIST,
  1537.                 $path);
  1538.         }
  1539.     }
  1540.     
  1541.     /**
  1542.      * Create the structure for a new package.xml
  1543.      *
  1544.      * @uses $_packageXml emulates reading in a package.xml
  1545.      *       by using the package, summary and description
  1546.      *       options
  1547.      * @return true|PEAR_Error
  1548.      * @access private
  1549.      */
  1550.     function _generateNewPackageXML()
  1551.     {
  1552.         $this->_oldPackageXml = false;
  1553.         if (!isset($this->_options['package'])) {
  1554.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOPACKAGE);
  1555.         }
  1556.         if (!isset($this->_options['summary'])) {
  1557.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NOSUMMARY);
  1558.         }
  1559.         if (!isset($this->_options['description'])) {
  1560.             return $this->raiseError(PEAR_PACKAGEFILEMANAGER_NODESC);
  1561.         }
  1562.         $this->_packageXml = array();
  1563.         $this->_packageXml['package'] = $this->_options['package'];
  1564.         $this->_packageXml['summary'] = $this->_options['summary'];
  1565.         $this->_packageXml['description'] = $this->_options['description'];
  1566.         $this->_packageXml['changelog'] = array();
  1567.         if ($this->_options['deps'] !== false) {
  1568.             $this->_packageXml['release_deps'] = $this->_options['deps'];
  1569.         } else {
  1570.             $this->_packageXml['release_deps'] = $this->_options['deps'] = array();
  1571.         }
  1572.         if ($this->_options['maintainers'] !== false) {
  1573.             $this->_packageXml['maintainers'] = $this->_options['maintainers'];
  1574.         } else {
  1575.             $this->_packageXml['maintainers'] = $this->_options['maintainers'] = array();
  1576.         }
  1577.         return true;
  1578.     }
  1579. }
  1580.  
  1581. if (!function_exists('file_get_contents')) {
  1582. /**
  1583.  * @ignore
  1584.  */
  1585. function file_get_contents($path, $use_include_path = null, $context = null)
  1586. {
  1587.     $a = @file($path, $use_include_path, $context);
  1588.     if (is_array($a)) {
  1589.         return implode('', $a);
  1590.     } else {
  1591.         return false;
  1592.     }
  1593. }
  1594. }
  1595. ?>